package com.ccsoft.netty.heartbeat.client;

import java.util.Random;

/**
 * @author chanchaw
 * @create 2022-07-20 16:45
 */
public class ExponentialBackOffRetry implements RetryPolicy{
    private static final int MAX_RETRIES_LIMIT = 29;// 最多重试次数
    private static final int DEFAULT_MAX_SLEEP_MS = Integer.MAX_VALUE;// 多大 sleep 时长 - 毫秒

    private final Random random = new Random();
    private final long baseSleepTimeMs;
    private final int maxRetries;
    private final int maxSleepMs;

    public ExponentialBackOffRetry(int baseSleepTimeMs, int maxRetries) {
        this(baseSleepTimeMs, maxRetries, DEFAULT_MAX_SLEEP_MS);
    }

    public ExponentialBackOffRetry(int baseSleepTimeMs, int maxRetries, int maxSleepMs) {
        this.maxRetries = maxRetries;
        this.baseSleepTimeMs = baseSleepTimeMs;
        this.maxSleepMs = maxSleepMs;
    }

    // 传入当前重试的次数，比对初始化时设定的最大重试次数，超过则返回 false 表示不再重试
    // 相反，返回 true 表示可以继续重试
    @Override
    public boolean allowRetry(int retryCount) {
        if (retryCount < maxRetries) {
            return true;
        }
        return false;
    }

    // 根据当前重试的次数计算本次sleep的时长
    @Override
    public long getSleepTimeMs(int retryCount) {
        if (retryCount < 0) {
            throw new IllegalArgumentException("retries count must greater than 0.");
        }
        if (retryCount > MAX_RETRIES_LIMIT) {
            System.out.println(String.format("maxRetries too large (%d). Pinning to %d", maxRetries, MAX_RETRIES_LIMIT));
            retryCount = MAX_RETRIES_LIMIT;
        }
        long sleepMs = baseSleepTimeMs * Math.max(1, random.nextInt(1 << retryCount));// 计算本次sleep时长
        if (sleepMs > maxSleepMs) {// 超过允许的最大sleep时长则打印异常
            System.out.println(String.format("Sleep extension too large (%d). Pinning to %d", sleepMs, maxSleepMs));
            sleepMs = maxSleepMs;
        }
        return sleepMs;
    }
}
